package drds.server.route;

import java.util.LinkedHashMap;
import java.util.Map;

import drds.server.execute_engine.data_handling.GroupByFilter;
import drds.server.sqlparser.sqlobject.statement.Statement;

/**
 * 对SQL进行解析之后的路由信息
 * 
 * @author 曹正辉<330937205@qq.com>
 */
public final class Route {
	/**
	 * 原始语句
	 */
	private String sql;

	private RouteNode[] routeNodes;
	private Statement statement;
	/**
	 * limit限制
	 */
	private int limitOffset;
	private int limitSize;

	private boolean cacheAble;
	/**
	 * cache table.primaryKey to datanode
	 */
	private String primaryKey;

	private DataMerge dataMerge;

	/**
	 * 是否为全局表，只有在insert、update、delete时会判断并修改。默认不是全局表，用于修正全局表修改数据的反馈。
	 */
	private boolean globalTable = false;

	// 是否完成了路由
	private boolean routeOk = false;

	// 是否自动提交，此属性主要用于记录ServerConnection上的autocommit状态
	private boolean autoCommit = true;

	// 是否可以在从库运行,此属性主要供RouteResultsetNode获取
	private Boolean writeTrue$ReadFalse;

	// 强制走 master，可以通过 RouteResultset的属性canRunInReadDB=false
	// 传给 RouteResultsetNode 来实现，但是 强制走 slave需要增加一个属性来实现:
	private Boolean masterTrue$SlaveFalse = null; // 默认null表示不施加影响

	public Boolean getMasterTrue$SlaveFalse() {
		return masterTrue$SlaveFalse;
	}

	public void setMasterTrue$SlaveFalse(Boolean masterTrue$SlaveFalse) {
		this.masterTrue$SlaveFalse = masterTrue$SlaveFalse;
	}

	public boolean isRouteOk() {
		return routeOk;
	}

	public void setFinishedRoute(boolean isFinishedRoute) {
		this.routeOk = isFinishedRoute;
	}

	public boolean isGlobalTable() {
		return globalTable;
	}

	public void setGlobalTable(boolean globalTable) {
		this.globalTable = globalTable;
	}

	public Route(String sql, int sqlType) {
		this.sql = sql;
		this.limitSize = -1;
	}

	public void resetNodes() {
		if (routeNodes != null) {
			for (RouteNode node : routeNodes) {
				node.resetSql();
			}
		}
	}

	public void copyLimitToNodes() {

		if (routeNodes != null) {
			for (RouteNode node : routeNodes) {
				if (node.getLimitSize() == -1 && //
						node.getLimitOffset() == 0) {
					node.setLimitOffset(limitOffset);
					node.setLimitCount(limitSize);
				}
			}

		}
	}

	public DataMerge getDataMerge() {
		return dataMerge;
	}

	public boolean isCache() {
		return cacheAble;
	}

	public void setCache(boolean cacheAble) {
		this.cacheAble = cacheAble;
	}

	public boolean needMerge() {
		return limitSize > 0 || dataMerge != null;
	}

	public boolean isHasAggrColumn() {
		return (dataMerge != null) && dataMerge.isHasAggregateColumn();
	}

	public int getLimitStart() {
		return limitOffset;
	}

	public String[] getGroupByColumns() {
		return (dataMerge != null) ? dataMerge.getGroupByColumns() : null;
	}

	private DataMerge createDataMergeIfNull() {
		if (dataMerge == null) {
			dataMerge = new DataMerge();
		}
		return dataMerge;
	}

	public Map<String, Integer> getMergeColumnAndIndexMap() {
		return (dataMerge != null) ? dataMerge.getMergeColumnAndIndexMap() : null;
	}

	public void setLimitOffset(int limitStart) {
		this.limitOffset = limitStart;
	}

	public String getPrimaryKey() {
		return primaryKey;
	}

	public boolean hasCachePrimaryKey() {
		return primaryKey != null;
	}

	public void setPrimaryKey(String primaryKey) {
		if (!primaryKey.contains(".")) {
			throw new java.lang.IllegalArgumentException("must be table.primarykey fomat :" + primaryKey);
		}
		this.primaryKey = primaryKey;
	}

	/**
	 * return primary key items ,first is table name ,seconds is primary key
	 */
	public String[] getPrimaryKeyItems() {
		return primaryKey.split("\\.");
	}

	public void setOrderByColumnMap(LinkedHashMap<String, Integer> orderByColumnMap) {
		if (orderByColumnMap != null && !orderByColumnMap.isEmpty()) {
			createDataMergeIfNull().setOrderByColumnMap(orderByColumnMap);
		}
	}

	public void setHasAggregateColumn(boolean hasAggregateColumn) {
		if (hasAggregateColumn) {
			createDataMergeIfNull().setHasAggregateColumn(true);
		}
	}

	public void setGroupByItemColumns(String[] groupByColumns) {
		if (groupByColumns != null && groupByColumns.length > 0) {
			createDataMergeIfNull().setGroupByColumns(groupByColumns);
		}
	}

	public void setMergeColumnAndIndexMap(Map<String, Integer> mergeColumnAndIndexMap) {
		if (mergeColumnAndIndexMap != null && !mergeColumnAndIndexMap.isEmpty()) {
			createDataMergeIfNull().setMergeColumnAndIndexMap(mergeColumnAndIndexMap);
		}

	}

	public LinkedHashMap<String, Integer> getOrderByColumnMap() {
		return (dataMerge != null) ? dataMerge.getOrderByColumnMap() : null;

	}

	public String getSql() {
		return sql;
	}

	public RouteNode[] getRouteNodes() {
		return routeNodes;
	}

	/**
	 * 为所有的路由节点信息添加节点数目
	 */
	public void setRouteNodes(RouteNode[] routeNodes) {
		if (routeNodes != null) {
			int length = routeNodes.length;
			for (RouteNode routeNode : routeNodes) {
				routeNode.setRouteNodeSize(length);
			}

		}
		this.routeNodes = routeNodes;
	}

	/**
	 * @return -1 if no limit
	 */
	public int getLimitSize() {
		return limitSize;
	}

	public void setLimitSize(int limitSize) {
		this.limitSize = limitSize;
	}

	public void setSql(String sql) {
		this.sql = sql;
	}

	public void updateLimit(String sql, int offset, int count) {
		if (routeNodes != null) {

			for (RouteNode routeNode : routeNodes) {
				// mysql之前已经加好limit
				routeNode.setNodeSql(sql);

				routeNode.setLimitOffset(offset);
				routeNode.setLimitCount(count);
			}

		}
	}

	public boolean isAutoCommit() {
		return autoCommit;
	}

	public void setAutoCommit(boolean autoCommit) {
		this.autoCommit = autoCommit;
	}

	public Boolean getWriteTrue$ReadFalse() {
		return writeTrue$ReadFalse;
	}

	public void setWriteTrue$ReadFalse(Boolean writeTrue$ReadFalse) {
		this.writeTrue$ReadFalse = writeTrue$ReadFalse;
	}

	public GroupByFilter getGroupByFilter() {
		return (dataMerge != null) ? dataMerge.getGroupByFilter() : null;
	}

	public void setGroupByFilter(GroupByFilter groupByFilter) {
		if (groupByFilter != null) {
			createDataMergeIfNull().setGroupByFilter(groupByFilter);
		}
	}

	public void setGroupByFilterColumNames(Object[] groupByFilterColumNames) {
		if (groupByFilterColumNames != null && groupByFilterColumNames.length > 0) {
			createDataMergeIfNull().setGroupByFilterColumNames(groupByFilterColumNames);
		}
	}

	public Statement getStatement() {
		return this.statement;
	}

	public void setStatement(Statement statement) {
		this.statement = statement;
	}

	public int getSqlType() {
		return 0;
	}

}